using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using RoofRunner.Base.Camera;
using RoofRunner.Base;


namespace RoofRunner.GameComponents.Controller
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class DebugMovementController : Microsoft.Xna.Framework.GameComponent
    {
        #region Fields
        private float _tmpMoveCos;
        private float _tmpMoveSin;
        private Nullable<MouseState> _oldMouseState;
        #endregion // Fields


        #region Properties
        private RoofRunnerGame RRGame { get { return (RoofRunnerGame)this.Game; } }

        public float RotationSpeed { get; set; }
        public float MovingSpeed { get; set; }
        #endregion // Properties


        #region Constructors
        public DebugMovementController(Game game)
            : base(game)
        {
            this.RotationSpeed = 2.0f;
            this.MovingSpeed = 0.1f;
        }
        #endregion // Constructors


        #region Methods
        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
        }


        #region Update
        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            SampleKeyboardInput(gameTime);
            SampleMouseInput(gameTime);
            base.Update(gameTime);
        }

        private void SampleKeyboardInput(GameTime gameTime)
        {
            var ks = Keyboard.GetState();
            if (ks.GetPressedKeys().Length <= 0) return; // No keys pressed

            Vector3 moveVector = Vector3.Zero;
            float dt = (float)gameTime.ElapsedGameTime.TotalSeconds * 60;
            float rotationSpeed = RotationSpeed * dt;


            if (ks.IsKeyDown(Keys.Left)) RRGame.Camera.Yaw += rotationSpeed;
            if (ks.IsKeyDown(Keys.Right)) RRGame.Camera.Yaw -= rotationSpeed;

            if (ks.IsKeyDown(Keys.Up)) RRGame.Camera.Pitch += rotationSpeed;
            if (ks.IsKeyDown(Keys.Down)) RRGame.Camera.Pitch -= rotationSpeed;

            float ryaw = MathHelper.ToRadians(RRGame.Camera.Yaw);

            _tmpMoveCos = (float)Math.Round((-Math.Cos(ryaw)), 10);
            _tmpMoveSin = (float)Math.Round((-Math.Sin(ryaw)), 10);

            if (ks.IsKeyDown(Keys.E)) moveVector += Vector3.Up;
            if (ks.IsKeyDown(Keys.Q)) moveVector += Vector3.Down;
            if (ks.IsKeyDown(Keys.W)) moveVector += new Vector3(_tmpMoveSin, 0.0f, _tmpMoveCos);
            if (ks.IsKeyDown(Keys.S)) moveVector -= new Vector3(_tmpMoveSin, 0.0f, _tmpMoveCos);
            if (ks.IsKeyDown(Keys.A)) moveVector += new Vector3(_tmpMoveCos, 0.0f, -_tmpMoveSin);
            if (ks.IsKeyDown(Keys.D)) moveVector += new Vector3(-_tmpMoveCos, 0.0f, _tmpMoveSin);


            float movingSpeed = this.MovingSpeed;
            if (ks.IsKeyDown(Keys.LeftShift)) movingSpeed *= 2;

            moveVector *= movingSpeed * dt;

            RRGame.Camera.Position += moveVector;
        }

        private void SampleMouseInput(GameTime gameTime)
        {
            var ms = Mouse.GetState();
            if (ms.RightButton == ButtonState.Pressed)
            {
                Game.IsMouseVisible = false;

                if (_oldMouseState != null)
                {
                    int omsx = _oldMouseState.Value.X;
                    int omsy = _oldMouseState.Value.Y;

                    int xd = ms.X - omsx;
                    int yd = ms.Y - omsy;

                    RRGame.Camera.Yaw -= xd;
                    RRGame.Camera.Pitch -= yd;

                    Mouse.SetPosition(omsx, omsy);
                }
                else
                    _oldMouseState = (Nullable<MouseState>)ms;
            }
            else
                _oldMouseState = null;
        }
        #endregion // Update
        #endregion // Methods
    }
}
